﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Pibby.Core.Tests.Stubs
{
	public enum DateGenerationOptions
	{
		LinearDays,
		FibonacciDays,
	}

	public class RssFeedGenerator : IGenerateContent
	{
		private StringBuilder _builder = new StringBuilder();

		#region Constructors
		
		public RssFeedGenerator ()
			: this (1)
		{
		}

		public RssFeedGenerator (int howManyItems)
			: this (howManyItems, DateTime.Today)
		{
		}

		public RssFeedGenerator (int howManyItems, DateTime fromDate)
			: this (howManyItems, fromDate, DateGenerationOptions.LinearDays)
		{
		}

		public RssFeedGenerator (int howManyItems, DateTime fromDate, DateGenerationOptions options)
		{
			RandomText randomText = new RandomText();
			randomText.Words.Add("a");
			randomText.Words.Add("our");
			randomText.Words.Add("your");
			randomText.Words.Add("its");
			randomText.Words.Add("politics");
			randomText.Words.Add("science");
			randomText.Words.Add("news");
			randomText.Words.Add("podcast");
			randomText.Words.Add("about");
			randomText.Words.Add("websites");

			randomText.Generate();

			this.PodcastTitle = "My Podcast";
			this.PodcastHomepage = "http://mypodcast.net/";
			this.PodcastDescription = randomText.ToString ();
			this.NonContiguousItems = false;

			this.HowManyItems = howManyItems;
			this.PublicationDate = fromDate;
			this.Options = options;
		}

		#endregion

		#region Properties

		public string PodcastTitle
		{
			get;
			set;
		}

		public string PodcastHomepage
		{
			get;
			set;
		}

		public string PodcastDescription
		{
			get;
			set;
		}

		public bool NonContiguousItems
		{
			get;
			set;
		}

		public int HowManyItems
		{
			get;
			set;
		}

		public DateTime PublicationDate
		{
			get;
			set;
		}

		public DateGenerationOptions Options
		{
			get;
			set;
		}

		public bool OmitEnclosureType
		{
			get;
			set;
		}

		public bool OmitEnclosureFileSize
		{
			get;
			set;
		}

		public bool OmitEnclosure 
		{
			get;
			set;
		}

		#endregion

		#region IGenerateContent

		public string Content
		{
			get
			{
				this.CreateFeed();

				return this._builder.ToString ();
			}
		}

		public TextReader ContentStream
		{
			get
			{
				return new StringReader(this.Content);
			}
		}
		#endregion

		private void CreateFeed()
		{
			BuildRssHeader();

			int firstFibonnaci = 0;
			int secondFibonnaci = 0;

			for (int i = 0; i < this.HowManyItems; ++i)
			{
				DateTime dt = this.PublicationDate;

				if (this.Options == DateGenerationOptions.LinearDays)
					dt = this.PublicationDate.AddDays(-i);
				else
				{
					int currentValue = firstFibonnaci + secondFibonnaci;

					dt = this.PublicationDate.AddDays(-currentValue);

					if (i == 0)
						currentValue = 1;

					firstFibonnaci = secondFibonnaci;
					secondFibonnaci = currentValue;
				}

				int episodeNumber = this.HowManyItems - i;

				// insert some random itunes nonsense generated by some rss editors
				// this makes SyndicationFeed choke.
				if (NonContiguousItems)
					this._builder.Append("<itunes:block>no</itunes:block>");

				BuildRssEpisode(episodeNumber, Guid.NewGuid().ToString(), dt);
			}

			BuildRssFooter();
		}

		private void BuildRssHeader()
		{
			this._builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			this._builder.Append("\n<rss xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" ");
			this._builder.Append("xmlns:wfw=\"http://wellformedweb.org/CommentAPI/\" ");
			this._builder.Append("xmlns:dc=\"http://purl.org/dc/elements/1.1/\" ");
			this._builder.Append("xmlns:atom=\"http://www.w3.org/2005/Atom\" ");
			this._builder.Append("xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\" ");
			this._builder.Append("xmlns:media=\"http://search.yahoo.com/mrss/\" ");
			this._builder.Append("xmlns:creativeCommons=\"http://backend.userland.com/creativeCommonsRssModule\" ");
			this._builder.Append("xmlns:feedburner=\"http://rssnamespace.org/feedburner/ext/1.0\" version=\"2.0\">");

			this._builder.Append("\n<channel>");
			this._builder.AppendFormat("\n<title>{0}</title>", this.PodcastTitle);

			this._builder.AppendFormat("\n<link>{0}</link>", this.PodcastHomepage);
			this._builder.AppendFormat("\n<description>{0}</description>", this.PodcastDescription);

			this._builder.AppendFormat("\n<pubDate>{0}</pubDate>", RssDateFormat(this.PublicationDate));
			this._builder.Append("\n<generator>NUnit test framework</generator>");
			this._builder.Append("\n<language>en</language>");
			this._builder.Append("\n<atom10:link xmlns:atom10=\"http://www.w3.org/2005/Atom\" rel=\"self\" href=\"http://escapepod.org/podcast.xml\" type=\"application/rss+xml\" />");
		}

		private void BuildRssEpisode(int episodeNumber, string guid, DateTime dt)
		{
			this._builder.Append("\n<item>");
			this._builder.AppendFormat("\n<title>Episode {0}</title>", episodeNumber);
			this._builder.AppendLine("<itunes:author>UnitTests</itunes:author>");
			this._builder.AppendLine("<itunes:keywords>audio, book, podast, free</itunes:keywords>");
			this._builder.AppendFormat("\n<link>{0}{1}/{2}/{3}/episode{4}/</link>", PodcastHomepage, dt.Year, dt.Month, dt.Day, episodeNumber);
			this._builder.AppendFormat("\n<pubDate>{0}</pubDate>", RssDateFormat(dt));
			this._builder.AppendLine("<itunes:subtitle>I think this is a fantastic podcast</itunes:subtitle>");
			this._builder.AppendLine("<itunes:summary>This lovely podcast is fantastic</itunes:summary>");
			this._builder.AppendLine("<category> Podcast</category>");
			this._builder.AppendLine("<itunes:explicit>no</itunes:explicit>");
			this._builder.AppendLine("<itunes:keywords>audio, book, free</itunes:keywords>");

			this._builder.Append("\n<dc:creator>UnitTests</dc:creator>");
			this._builder.AppendFormat("\n<guid isPermaLink=\"false\">http://mypodcast.net/?p={0}</guid>", guid); //Guid.NewGuid().ToString());



			if (this.OmitEnclosure)
			{
				// hide the link in the description - some unscrupulous podcasts actually do this :)
				this._builder.AppendFormat("\n<description><![CDATA[<p><font size=\"2\">Description for episode {0} goes <a href=\"http://media.mypodcast.net/media/mypodcast/EP_{1}.mp3\">here</a></font></p> <br /> ]]></description>", episodeNumber, episodeNumber);
			}
			else
			{
				this._builder.AppendFormat("\n<description>Description for episode {0} goes here</description>", episodeNumber);
				this._builder.AppendFormat("\n<enclosure url=\"http://media.mypodcast.net/media/mypodcast/EP_{0}.mp3\" length=\"{1}\" type=\"{2}\" />", 
											episodeNumber, 
											(this.OmitEnclosureFileSize ? 0 : 100 + (episodeNumber * 1024)),
											(this.OmitEnclosureType ? "" : "audio/mpeg"));
			}

			this._builder.Append("\n</item>");
		}

		private void BuildRssFooter()
		{
			this._builder.Append("\n</channel>");
			this._builder.Append("\n</rss><!-- Dynamic Page Served (once) in 1.756 seconds -->");
		}


		private string RssDateFormat(DateTime dt)
		{
			// RFC822 format
			return string.Format("{0:ddd, dd MMM yyyy HH:mm:ss} +0000", dt);
		}

	}
}

